package com.xinyues.gamemanager.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xinyues.gamemanager.common.GmBusinessException;
import com.xinyues.gamemanager.common.StringUtil;
import com.xinyues.gamemanager.dao.MenuRepository;
import com.xinyues.gamemanager.dao.PermissionRepository;
import com.xinyues.gamemanager.dao.entity.GmAccount;
import com.xinyues.gamemanager.dao.entity.GmMenu;
import com.xinyues.gamemanager.dao.entity.GmPermission;
import com.xinyues.gamemanager.dao.entity.GmRole;
import com.xinyues.gamemanager.dao.entity.model.MenuNode;
import com.xinyues.gamemanager.dao.entity.model.Permission;
import com.xinyues.gamemanager.vo.VOPermission;

@Service
public class GmMenuService {
    private Logger logger = LoggerFactory.getLogger(GmMenuService.class);
    @Autowired
    private MenuRepository menuRepository;
    @Autowired
    private PermissionRepository permissionRepository;
    @Autowired
    private GmRoleService roleService;

    public GmMenu getGmMenu() {
        List<GmMenu> menus = menuRepository.findAll();
        if (menus.isEmpty()) {
            GmMenu gmMenu = new GmMenu();
            List<MenuNode> menuNodes = gmMenu.getMenuNodes();
            MenuNode defaultMenuNode = new MenuNode();
            defaultMenuNode.setId(StringUtil.uuid());
            defaultMenuNode.setText("GM系统管理");
            MenuNode menuNode = new MenuNode();
            menuNode.setId(StringUtil.uuid());
            menuNode.setText("菜单管理");
            menuNode.setHref("/gm-center/layout/toMenuManager");
            menuNode.setParentId(defaultMenuNode.getId());
            List<MenuNode> systemNodes = new ArrayList<>();
            systemNodes.add(menuNode);
            defaultMenuNode.setChildren(systemNodes);
            menuNodes.add(defaultMenuNode);
            return gmMenu;
        } else {
            return menus.get(0);
        }
    }

    /**
     * 
     * <p>
     * Description: 获取当前用户的角色所拥有的所有的菜单,角色id查出当前角色信息->查出权限信息->此权限的菜单Id->此菜单的所有父类菜单id
     * </p>
     * 
     * @param roleId
     * @return
     * @author wang guang shuai
     * @date 2019年12月11日 下午6:50:07
     *
     */
    private Set<String> getAllMenuIdListOfRole(String roleId) {
        Set<String> allMenuIds = new HashSet<>();
        GmRole gmRole = roleService.getRole(roleId);
        GmMenu menu = this.getGmMenu();
        gmRole.getChildren().forEach(m -> {
            allMenuIds.add(m.getId());// 权限菜单
            Set<String> parentIds = new HashSet<>();
            this.getAllParentMenuId(m.getId(), menu, parentIds);
            allMenuIds.addAll(parentIds);
        });
        return allMenuIds;
    }

    private void getAllParentMenuId(String menuId, GmMenu menu, Set<String> parentIds) {
        MenuNode menuNode = this.getMenuNodeByMenuId(menu, menuId);
        if (menuNode != null) {
            parentIds.add(menuId);
            if (menuNode.getParentId() != null) {
                this.getAllParentMenuId(menuNode.getParentId(), menu, parentIds);
            }
        }
    }

    public String getMenuHtml(GmMenu gmMenu, GmAccount gmAccount) {
        if(gmAccount == null || gmAccount.getRoles().isEmpty()) {
            return "";
        }
        List<MenuNode> menuNodes = gmMenu.getMenuNodes();
        Set<String> allMeueIds = this.getAllMenuIdListOfRole(gmAccount.getRoles().get(0));
        StringBuilder buff = new StringBuilder();
        buff.append("<ul class=\"layui-nav layui-nav-tree\" lay-filter=\"test\">").append("\n");
        for (MenuNode menuNode : menuNodes) {
            if(!allMeueIds.contains(menuNode.getId())) {
                continue;
            }
            buff.append("<li class=\"layui-nav-item layui-nav-itemed\">").append("\n");
            buff.append("<a class=\"\" href=\"javascript:;\">").append(menuNode.getText()).append("</a>").append("\n");
            if (!menuNode.getChildren().isEmpty()) {
                this.append(menuNode.getChildren(), buff,allMeueIds);
            }

            buff.append("</li>");
        }
        buff.append("</ul>");
        String menuHtml = buff.toString();
        logger.debug(menuHtml);
        return menuHtml;
    }

    private void append(List<MenuNode> menuNodes, StringBuilder buff,Set<String> allParentIds) {
        if (menuNodes.isEmpty()) {
            return;
        }
        buff.append("<dl class=\"layui-nav-child\">").append("\n");
        for (MenuNode menuNode : menuNodes) {
            if(!allParentIds.contains(menuNode.getId())) {
                continue;
            }
            buff.append("<dd>").append("\n");
            if (menuNode.getHref() != null) {
                buff.append("<a href=\"" + menuNode.getHref() + "\" target=\"main_center\">");
            } else {
                buff.append("<a href=\"javascript:;\">");
            }
            buff.append("\n");
            buff.append(menuNode.getText()).append("</a>");
            if (!menuNode.getChildren().isEmpty()) {
                this.append(menuNode.getChildren(), buff,allParentIds);
            }
            buff.append("</dd>").append("\n");

        }
        buff.append("<dl>").append("\n");
    }

    public List<MenuNode> getMenuNodeList(GmMenu menu) {
        List<MenuNode> menuNodes = new ArrayList<>();
        menu.getMenuNodes().forEach(menuNode -> {
            menuNodes.add(menuNode);
            this.addMenuList(menuNodes, menuNode);
        });
        return menuNodes;
    }

    private void addMenuList(List<MenuNode> menuNodes, MenuNode menuNode) {
        if (!menuNode.getChildren().isEmpty()) {
            menuNode.getChildren().forEach(m -> {
                menuNodes.add(m);
                this.addMenuList(menuNodes, m);
            });
        }
    }

    public void addOrUpdateMenu(GmMenu menu, MenuNode menuNode) {
        if(menuNode.getParentId().equals("-1")) {
            menuNode.setParentId(null);
        }
        if (menuNode.getId() == null) {
            String menuId = StringUtil.uuid();
            menuNode.setId(menuId);
        }
        if (menuNode.getParentId() == null) {
            menu.getMenuNodes().add(menuNode);
        } else {
            menu.getMenuNodes().forEach(m -> {
                this.findAndAddMenu(m, menuNode);
            });
        }
        menuRepository.save(menu);
    }

    private void findAndAddMenu(MenuNode menuNode, MenuNode newNode) {
        if (menuNode.getId().equals(newNode.getParentId())) {
            menuNode.getChildren().add(newNode);
        } else {
            if (!menuNode.getChildren().isEmpty()) {
                menuNode.getChildren().forEach(m -> {
                    this.findAndAddMenu(m, newNode);
                });
            }
        }
    }

    public void deleteMenu(GmMenu gmMenu, String menuId) {
        boolean result = gmMenu.getMenuNodes().removeIf(m -> m.getId().equals(menuId));
        if (!result) {
            gmMenu.getMenuNodes().forEach(m -> {
                this.deleteMenuByRecursion(m, menuId);
            });
        }
        menuRepository.save(gmMenu);
    }

    private void deleteMenuByRecursion(MenuNode menuNode, String menuId) {
        if (!menuNode.getChildren().isEmpty()) {
            boolean result = menuNode.getChildren().removeIf(m -> m.getId().equals(menuId));
            if (!result) {
                menuNode.getChildren().forEach(m -> {
                    this.deleteMenuByRecursion(m, menuId);
                });
            }
        }
    }

    private MenuNode getMenuNodeByMenuId(String menuId) {
        GmMenu gmMenu = this.getGmMenu();
        return this.getMenuNodeByMenuId(gmMenu, menuId);
    }

    public MenuNode getMenuNodeByMenuId(GmMenu menu, String menuId) {
        MenuNode menuNode = this.findMenuNodeByRecursion(menu.getMenuNodes(), menuId);
        return menuNode;
    }

    private MenuNode findMenuNodeByRecursion(List<MenuNode> menuNodes, String menuId) {
        for (MenuNode item : menuNodes) {
            if (item.getId().equals(menuId)) {
                return item;
            } else {
                MenuNode result = this.findMenuNodeByRecursion(item.getChildren(), menuId);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    public List<VOPermission> getPermission() {
        List<GmPermission> gmPermissions = permissionRepository.findAll();
        List<VOPermission> voPermissions = new ArrayList<>(gmPermissions.size());
        gmPermissions.forEach(p -> {
            VOPermission permission = new VOPermission();
            permission.setChildren(p.getChildren());
            permission.setId(p.getId());
            MenuNode menuNode = this.getMenuNodeByMenuId(p.getId());
            if (menuNode != null) {
                permission.setText(menuNode.getText());
                voPermissions.add(permission);
            }
        });
        return voPermissions;
    }

    public void addPermission(String menuId, Permission permission) {
        GmPermission gmPermission = this.permissionRepository.findById(menuId).orElse(null);
        if (gmPermission == null) {
            gmPermission = new GmPermission();
            gmPermission.setId(menuId);
        }
        permission.setId(StringUtil.uuid());
        permission.setParentId(menuId);
        gmPermission.getChildren().add(permission);
        this.permissionRepository.save(gmPermission);
    }

    public void deletePermission(String menuId, String pid) {
        GmPermission gmPermission = this.permissionRepository.findById(menuId).orElse(null);
        if (gmPermission == null) {
            throw new GmBusinessException("所属父类菜单不存在:" + menuId);
        }
        boolean result = gmPermission.getChildren().removeIf(p -> p.getId().equals(pid));
        if (result) {
            this.permissionRepository.save(gmPermission);
        }
    }

    public GmPermission getGmPermission(String menuId) {
        GmPermission gmPermission = this.permissionRepository.findById(menuId).orElse(null);
        return gmPermission;
    }
}
